
import Foundation

class Lander {
    var url = ""
    var osnID = ""
    var osnKey = ""
    var target = ""
    var callback:(([String:Any]?, String?)->Void)?
    var username:String?
    
    var serviceID = ""
    var serverInfo = ""
    var randClient:UInt64 = 0
    var randServer:UInt64 = 0
    var sign = ""
    var hash = ""
    var session = ""
    init(url: String = "", osnID: String = "", osnKey: String = "", target: String = "", callback: ( ([String : Any]?, String?) -> Void)? = nil) {
        self.url = url
        self.osnID = osnID
        self.osnKey = osnKey
        self.target = target
        self.callback = callback
    }
    func GetServerInfo() async -> [String:Any]? {
        randClient = DispatchTime.now().uptimeNanoseconds/1_000_000
        var json:[String:Any] = [:]
        json["command"] = "GetServerInfo"
        json["user"] = osnID
        json["random"] = randClient
        //print("GetServerInfo data: \(json)")
        guard let data = await DappSdk.doPost(url, OsnUtils.toString(json) ?? "", nil) else {
            callback?(nil, "GetServerInfo failure")
            return nil
        }
        //print("GetServerInfo result: \(data)");
        guard let json = data.toJson() else {
            callback?(nil, "invalid GetServerInfo result")
            return nil
        }
        return json
    }
    func CheckServerInfo(json:[String:Any]) -> Bool {
        serviceID = json["serviceID"] as? String ?? ""
        randServer = json["random"] as? UInt64 ?? 0
        serverInfo = json["serviceInfo"] as? String ?? ""
        session = json["session"] as? String ?? ""

        if serviceID != target {
            callback?(nil, "serviceID no equals litappID: " + target + ", serviceID: " + serviceID)
            return false
        }
        
        let data = osnID + String(randClient) + serviceID + String(randServer) + serverInfo
        hash = DappSdk.dappHash(data: data.data(using: .utf8)!)
        sign = json["sign"] as? String ?? ""
        //print("sign data: \(data)")
        if hash != json["hash"] as? String ?? "" || !DappSdk.dappVerify(osnID: serviceID, hash: hash.data(using: .utf8)!, sign: sign){
            callback?(nil, "verify error")
            return false
        }
        return true
    }
    func LoginServer() async -> [String:Any]? {
        let data = serviceID + String(randServer) + osnID + String(randClient)
        let hash = DappSdk.dappHash(data: data.data(using: .utf8)!)
        guard let sign = DappSdk.dappSign(key: osnKey, data: hash.data(using: .utf8)!) else {
            callback?(nil, "sign error")
            return nil
        }
        var json:[String:Any] = [:]
        json["command"] = "Login"
        json["user"] = osnID
        json["hash"] = hash
        json["sign"] = sign
        json["session"] = session
        if let username = username {
            json["username"] = username
        }
        //print("Login data: \(json)")
        guard let data = await DappSdk.doPost(url, OsnUtils.toString(json) ?? "", nil) else {
            callback?(nil, "Login failure")
            return nil
        }
        //print("Login result: \(data)");
        
        guard let json = data.toJson() else {
            callback?(nil, "invalid Login result")
            return nil
        }
        if !DappSdk.isSuccess(json) {
            callback?(nil, DappSdk.errCode(json))
            return nil
        }
        return json
    }
    func GetLoginSession(json:[String:Any]) -> [String:Any]? {
        guard let sessionKey = json["sessionKey"] as? String else {
            callback?(nil, "no find sessionKey")
            return nil
        }
        guard let decKey = EcUtils.ecDecrypt2(priKey: osnKey, data: sessionKey) else {
            callback?(nil, "ecDecrypt2 failure")
            return nil
        }
        var data = String(data: decKey, encoding: .utf8)!
        //print("decrypt data: \(data)");
        if let zero = data.firstIndex(of: "\0") {
            data = String(data[..<zero])
            //print("trim zero padding: \(data)")
        }
        guard let json = data.toJson() else {
            callback?(nil, "invalid Login result")
            return nil
        }
        callback?(json, nil)
        return json
    }
    func dappLogin() async -> [String:Any]? {
        guard let json = await GetServerInfo() else {return nil}
        if !CheckServerInfo(json: json) {return nil}
        guard let json = await LoginServer() else {return nil}
        return GetLoginSession(json: json)
    }
    
}
//extension String {
//    /// 将字符串解析为 JSON 字典。如果字符串不是有效的 JSON 或为空，则返回 nil。
//    func toJson() -> [String: Any]? {
//        guard let data = self.data(using: .utf8) else {
//            // 如果无法将字符串转换为 UTF-8 数据，则返回 nil
//            return nil
//        }
//          
//        do {
//            if let dict = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
//                return dict
//            }
//            // 如果 JSON 不是字典类型，则隐式返回 nil
//        } catch {
//            //print("Failed to decode JSON string: \(error.localizedDescription)")
//            // 打印错误，但按照当前实现，我们仍然返回 nil
//        }
//          
//        return nil
//    }
//}
//  
//extension [String: Any] {
//    /// 将 JSON 字典转换为字符串。如果序列化失败，则返回 nil。
//    func toString() -> String? {
//        do {
//            let data = try JSONSerialization.data(withJSONObject: self, options: [])
//            if let string = String(data: data, encoding: .utf8) {
//                return string
//            }
//            // 如果无法将数据转换为 UTF-8 字符串，则隐式返回 nil
//        } catch {
//            // 这里可以抛出一个更具体的错误，但简单起见，我们打印错误并返回 nil
//            //print("Failed to encode JSON string: \(error.localizedDescription)")
//        }
//          
//        return nil
//    }
//} 
